using System;
using System.Linq;
using System.Runtime;
using Godot;
using Godot.Collections;

public partial class TileMapBase : Godot.TileMap
{
    TileDataInfo tileData = new TileDataInfo();

    private Vector2I initPos = new Vector2I();

    private Array<Vector2I> pathTileData = new Array<Vector2I>();
    private TileMapLayerName mainLayer = TileMapLayerName.BACKGROUND;
    /// <summary>
    /// 改变层显示
    /// </summary>
    /// <param name="tileMap">tilemap组件</param>
    /// <param name="layer">层名称，来自枚举TileMapLayerName</param>
    /// <param name="type">是否显示，true or false</param>
    public void EnableLayer(TileMapLayerName layer, bool type)
    {
        string name = GetLayerName((int)layer);
        if (name is not null)
        {
            SetLayerEnabled((int)layer, type);
        }

    }

    public bool CheckLayerIsShow(TileMapLayerName layer)
    {
        return IsLayerEnabled((int)layer);
    }



    /// <summary>
    /// 获取角色可以行走的范围
    /// </summary>
    /// <param name="tileMap">tilemap组件</param>
    /// <param name="actorPos">角色当前位置</param>
    /// <param name="actorInfo">角色信息类</param>
    public TileDataInfo ShowActorCanMoveTileRange(Vector2I actorPos, ActorBase actorInfo)
    {
        //获取角色可以行走的所有地块坐标
        int range = actorInfo.leftMoveRange;

        TileDataInfo canMoveList = GetCanWalkTileList(actorPos, range);

        EnableLayer(TileMapLayerName.CANWALK, true);

        ClearLayer((int)TileMapLayerName.CANWALK);  // 清理所有地块信息

        foreach (Vector2I vec in canMoveList.getAllPostList())
        {
            SetCell((int)TileMapLayerName.CANWALK, vec, 1, new Vector2I(0, 0));
        }
        GD.Print(canMoveList.getAllPostList());
        return canMoveList;
    }

    /// <summary>
    /// 获取角色可以行走的范围
    /// </summary>
    /// <param name="tileMap">tilemap组件</param>
    /// <param name="actorPos">角色当前位置</param>
    /// <param name="actorInfo">角色信息类</param>
    public TileDataInfo ShowActorCanMoveTileRangeByStep(Vector2I actorPos, int step)
    {
        //获取角色可以行走的所有地块坐标
        TileDataInfo canMoveList = GetCanWalkTileList(actorPos, step);

        EnableLayer(TileMapLayerName.CANWALK, true);

        ClearLayer((int)TileMapLayerName.CANWALK);  // 清理所有地块信息

        foreach (Vector2I vec in canMoveList.getAllPostList())
        {
            SetCell((int)TileMapLayerName.CANWALK, vec, 1, new Vector2I(0, 0));
        }
        GD.Print(canMoveList.getAllPostList());
        return canMoveList;
    }


    //-------------------------------------------------------------------------------------  获取可以行走区域模块----------------------------------------------------------------//
    private static TileDataInfo rangeList = new TileDataInfo();
    private static int range = 0;

    private static Rect2I map = new Rect2I();

    static Vector2I tempv2 = new Vector2I();

    //private static Array<Vector2I> flagVec = new Array<Vector2I> { new Vector2I(1, 0), new Vector2I(0, 1), new Vector2I(-1, 0), new Vector2I(0, -1) };

    private void GotoNextStep(Vector2I point, int leftStep, Array<Vector2I> flagVec, bool isBegin = false)
    {

        //首先检测四个方向是否可以行走
        foreach (Vector2I vec2 in flagVec)
        {
            tempv2.X = point.X + vec2.X;
            tempv2.Y = point.Y + vec2.Y;
            if (tempv2.X >= map.Position.X && tempv2.Y >= map.Position.Y && tempv2.X <= map.End.X && tempv2.Y <= map.End.Y)   //检测坐标是否合法
            {
                TileData cell = GetCellTileData((int)TileMapLayerName.BACKGROUND, tempv2);
                int needPassStep = (int)cell.GetCustomData("moveSpeed") >= 0 ? (int)cell.GetCustomData("moveSpeed") : 1;
                int nextStepLeftStep = leftStep - needPassStep;
                bool isCanWalk = (bool)cell.GetCustomData("isCanWalk");
                //判断当前剩余步数是否大于已存在的剩余步数

                if (!rangeList.ContainsPos(tempv2))   //检测是否已经存在当前坐标
                {
                    if (nextStepLeftStep >= 0 && isCanWalk)  //检测步数是否足够
                    {
                        GD.Print(tempv2 + "   " + (bool)cell.GetCustomData("isCanWalk"), flagVec);
                        rangeList.Add(tempv2, cell);
                        rangeList.SetConnectPoint(point, tempv2);
                        //canWalkList.Add(tempv2, nextStepLeftStep);
                        if (!isBegin)
                        {

                            //非初始状态只需要3个方向
                            if (vec2.X != 0)
                            {
                                GotoNextStep(tempv2, nextStepLeftStep, new Array<Vector2I> { new Vector2I(vec2.X, 0), new Vector2I(0, 1), new Vector2I(0, -1) });
                            }
                            else
                            {
                                GotoNextStep(tempv2, nextStepLeftStep, new Array<Vector2I> { new Vector2I(1, 0), new Vector2I(-1, 0), new Vector2I(0, vec2.Y) });
                            }

                        }
                        else
                        {
                            //初始状态需要4个方向
                            GotoNextStep(tempv2, nextStepLeftStep, flagVec);
                        }

                    }
                }
                else
                {
                    GD.Print("这里是存在的", tempv2 + "   " + nextStepLeftStep);
                    //仅仅计算连通性
                    rangeList.SetConnectPoint(point, tempv2);
                }

            }

        }
        GD.Print("第几回护额" + point + "  ", isBegin);
    }


    /// <summary>
    /// 获取可以行走地块
    /// </summary>
    /// <param name="sourceTileMap"> tilemap组件</param>
    /// <param name="beginPos">角色所在区域</param>
    /// <param name="walkRange"></param>
    /// <returns></returns>
    public TileDataInfo GetCanWalkTileList(Vector2I beginPos, int walkRange)
    {
        rangeList.Clear();
        range = walkRange;
        TileData beginData = GetCellTileData((int)TileMapLayerName.BACKGROUND, beginPos);
        rangeList.SetBeginPoint(beginPos, beginData);
        map = GetUsedRect();
        //计算四方通路
        GotoNextStep(beginPos, range, new Array<Vector2I> { new Vector2I(1, 0), new Vector2I(-1, 0), new Vector2I(0, 1), new Vector2I(0, -1) }, true);

        return rangeList;
    }

    /// <summary>
    /// 根据角色类获取可以行走的区域
    /// </summary>
    /// <param name="sourceTileMap"></param>
    /// <param name="beginPos"></param>
    /// <param name="actor"></param>
    /// <returns></returns>
    public TileDataInfo GetCanWalkTileListByActor(Vector2I beginPos, ActorBase actor)
    {
        return GetCanWalkTileList(beginPos, actor.moveRange);

    }

    // ----------------------------------------------------------------------------- 获取可以行走区域模块结束 ----------------------------------------------------------------------------//

    // ------------------------------------------------------------ 寻路模块开始 ----------------------------------------------------//

    /// <summary>
    /// 根据初始位置和结束位置，以及可行走区域设置路径
    /// </summary>
    /// <param name="sourceTileMap"></param>
    /// <param name="beginPos"></param>
    /// <param name="endPos"></param>
    /// <param name="walkList"></param>
    /// <returns></returns>
    public Array<Vector2I> FindWayInCanWalkLayer(Vector2I beginPos, Vector2I endPos, TileDataInfo walkList)
    {
        Array<Vector2I> result = new Array<Vector2I>();
        Array<Vector2I> path = walkList.GetPathBeginToEnd(beginPos, endPos);
        ClearLayer((int)TileMapLayerName.PATH);
        EnableLayer(TileMapLayerName.PATH, true);
        if (path.Count > 0)
        {
            foreach (Vector2I vec in path)
            {
                SetCell((int)TileMapLayerName.PATH, vec, 1, new Vector2I(1, 0));
                result.Add(vec);
            }
        }


        return result;
    }
    //-------------------------------------------------------------寻路模块结束-----------------------------------------------------//



    //------------------------------设置可放置人物地块------------------------//
    public void SetCanPutActorArea(Array<Vector2I> areaList)
    {
        EnableLayer(TileMapLayerName.BEGINPOS, true);
        foreach (Vector2I vec in areaList)
        {
            SetCell((int)TileMapLayerName.BEGINPOS, vec, 1, new Vector2I(1, 0));

        }
    }

    /*public static void ClearLayer(Godot.TileMap sourceTileMap, TileMapLayerName name)
    {
        sourceTileMap.ClearLayer((int)name);  // 清理所有地块信息
    }*/


    public void InitMap()
    {
        ClearLayer((int)TileMapLayerName.BEGINPOS);
        ClearLayer((int)TileMapLayerName.CANWALK);
        ClearLayer((int)TileMapLayerName.PATH);
        ClearLayer((int)TileMapLayerName.ATTACKRANGE);

        EnableLayer(TileMapLayerName.BACKGROUND, true);
        EnableLayer(TileMapLayerName.BEGINPOS, false);
        EnableLayer(TileMapLayerName.CANWALK, false);
        EnableLayer(TileMapLayerName.PATH, false);
        EnableLayer(TileMapLayerName.ATTACKRANGE, false);
    }

    public override void _Input(InputEvent @event)
    {
        base._Input(@event);

        if (@event.IsPressed())
        {
            Vector2 pos = GetViewport().GetMousePosition();
            Vector2I endPos = TileMapUtil.ChangePosToTile(pos.X, pos.Y);
            if (pathTileData.Contains(endPos) && CheckLayerIsShow(TileMapLayerName.CANWALK))
            {

                EventParams param = new EventParams();
                param.paramDict.Add("pathData", pathTileData);
                EventManager.getInstance().dispatchEvent(EventType.EVENT_TILE_MAP_ACTOR_MOVE, param);

            }
            else
            {
                if (tileData.ContainsPos(endPos) && CheckLayerIsShow(TileMapLayerName.CANWALK))  //行走界面打开且点击有数据
                {
                    pathTileData = FindWayInCanWalkLayer(initPos, endPos, tileData);
                }
                else
                {
                    GD.Print("点的不是地方");
                }
            }




        }


    }
}

public class TileDataInfo
{
    private Array<Vector2I> posList = new Array<Vector2I>();

    private Array<TileData> cellList = new Array<TileData>();

    private AStar2D astar = new AStar2D();

    private Dictionary<Vector2I, int> vecDict = new Dictionary<Vector2I, int>();

    private Dictionary<int, Vector2I> intDict = new Dictionary<int, Vector2I>();

    private int id = 1;

    private Vector2I beginPoint = new Vector2I();

    public void Add(Vector2I pos, TileData cell)
    {
        posList.Add(pos);
        cellList.Add(cell);

    }

    public void SetBeginPoint(Vector2I pos, TileData cell)
    {
        astar.Clear();
        astar.AddPoint(id, pos);

        id = 1;
        vecDict.Clear();


        vecDict[pos] = 1;
        intDict[1] = pos;
        beginPoint = pos;
        Add(pos, cell);

    }

    public void SetConnectPoint(Vector2I prePos, Vector2I pos)
    {

        if (vecDict.ContainsKey(prePos))
        {
            if (vecDict.ContainsKey(pos))
            {
                //存在仅仅判断是否连接
                int preId = vecDict[prePos];
                int posId = vecDict[pos];
                if (!astar.ArePointsConnected(preId, posId))
                {
                    //没有连接则直接连接
                    astar.ConnectPoints(preId, posId);
                }
            }
            else
            {
                //不存在结束点，则需要添加连接和点
                id++;
                astar.AddPoint(id, pos);
                int preId = vecDict[prePos];
                astar.ConnectPoints(preId, id);

                vecDict[pos] = id;
                intDict[id] = pos;
            }

        }

    }

    public Array<Vector2I> GetPathPointFromBeginPoint(Vector2I endPos)
    {

        Array<Vector2I> result = new Array<Vector2I>();
        if (vecDict.ContainsKey(endPos))
        {
            long[] path = astar.GetIdPath(1, vecDict[endPos]);
            for (int i = 0; i <= path.Length - 1; i++)
            {
                result.Add(intDict[(int)path[i]]);
            }
        }
        return result;
    }

    public Array<Vector2I> GetPathBeginToEnd(Vector2I beginPos, Vector2I endPos)
    {
        Array<Vector2I> result = new Array<Vector2I>();
        if (vecDict.ContainsKey(endPos) && vecDict.ContainsKey(beginPos))
        {
            long[] path = astar.GetIdPath(vecDict[beginPos], vecDict[endPos]);
            for (int i = 0; i <= path.Length - 1; i++)
            {
                result.Add(intDict[(int)path[i]]);
            }
        }
        return result;
    }

    public bool ContainsPos(Vector2I pos)
    {
        return posList.Contains<Vector2I>(pos);

    }

    public Array<Vector2I> getAllPostList()
    {
        return posList;
    }

    public void Clear()
    {
        vecDict.Clear();
        posList.Clear();
        cellList.Clear();
        id = 1;
        astar.Clear();
    }
}